home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- ripple.c
- Drew Olbrich, 1992
-
- This distortion effect approximates looking down at an
- image through a layer of water. The user can poke
- at the water using the mouse, generating one or more
- ripple patterns.
-
- To create the effect, an large texture image is mapped
- onto a mesh of polygons. Only the texture coordinates of
- the polygon vertices are distorted -- not the vertex
- coordinates.
- */
-
- #include <stdio.h>
- #include <math.h>
- #include <gl.h>
- #include <device.h>
-
- #include "defs.h"
- #include "ripple.h"
-
- EFFECT ripple = { ripple_init, ripple_dynamics, ripple_redraw, ripple_click };
-
- static RIPPLE_VERTEX ripple_vertex[GRID_SIZE_X][GRID_SIZE_Y];
-
- static int cx[RIPPLE_COUNT];
- static int cy[RIPPLE_COUNT];
- static int t[RIPPLE_COUNT];
- static int max[RIPPLE_COUNT];
-
- static int ripple_max;
-
- /*
- Initialize ripple location and age information.
-
- Also, precompute the vertex coordinates and the default texture
- coordinates assigned to them.
- */
-
- void ripple_init()
- {
- int i, j;
-
- zbuffer(FALSE);
-
- ripple_max = (int) sqrt(WIN_SIZE_X*WIN_SIZE_X + WIN_SIZE_Y*WIN_SIZE_Y);
-
- for (i = 0; i < RIPPLE_COUNT; i++)
- {
- t[i] = ripple_max + RIPPLE_LENGTH;
- cx[i] = 0;
- cy[i] = 0;
- max[i] = 0;
- }
-
- for (i = 0; i < GRID_SIZE_X; i++)
- for (j = 0; j < GRID_SIZE_Y; j++)
- {
- ripple_vertex[i][j].x[0] = i/(GRID_SIZE_X - 1.0)*WIN_SIZE_X;
- ripple_vertex[i][j].x[1] = j/(GRID_SIZE_Y - 1.0)*WIN_SIZE_Y;
- ripple_vertex[i][j].dt[0] = i/(GRID_SIZE_X - 1.0);
- ripple_vertex[i][j].dt[1] = j/(GRID_SIZE_Y - 1.0);
- }
- }
-
- /*
- Advance one time step and compute new texture coordinates
- for the next frame of animation.
- */
-
- void ripple_dynamics(int mousex, int mousey)
- {
- int i, j, k;
- int x, y;
- int mi, mj;
- int r;
- float sx, sy;
- float amp;
-
- for (i = 0; i < RIPPLE_COUNT; i++)
- t[i] += RIPPLE_STEP;
-
- for (i = 0; i < GRID_SIZE_X; i++)
- for (j = 0; j < GRID_SIZE_Y; j++)
- {
- ripple_vertex[i][j].t[0] = ripple_vertex[i][j].dt[0];
- ripple_vertex[i][j].t[1] = ripple_vertex[i][j].dt[1];
-
- for (k = 0; k < RIPPLE_COUNT; k++)
- {
- x = i - cx[k];
- y = j - cy[k];
- if (x < 0)
- {
- x *= -1;
- sx = -1.0;
- }
- else
- sx = 1.0;
- if (y < 0)
- {
- y *= -1;
- sy = -1.0;
- }
- else
- sy = 1.0;
- mi = x;
- mj = y;
-
- r = t[k] - ripple_vector[mi][mj].r;
-
- if (r < 0)
- r = 0;
- if (r > RIPPLE_LENGTH - 1)
- r = RIPPLE_LENGTH - 1;
-
- amp = 1.0 - 1.0*t[k]/RIPPLE_LENGTH;
- amp *= amp;
- if (amp < 0.0)
- amp = 0.0;
-
- ripple_vertex[i][j].t[0]
- += ripple_vector[mi][mj].dx[0]*sx*ripple_amp[r].amplitude*amp;
- ripple_vertex[i][j].t[1]
- += ripple_vector[mi][mj].dx[1]*sy*ripple_amp[r].amplitude*amp;
- }
- }
- }
-
- /*
- Draw the next frame of animation.
- */
-
- void ripple_redraw()
- {
- int i, j;
-
- cpack(0xFFFFFFFF);
-
- for (i = 0; i < GRID_SIZE_X - 1; i++)
- {
- for (j = 0; j < GRID_SIZE_Y - 1; j++)
- {
- bgnpolygon();
- t2f(ripple_vertex[i][j].t);
- v2f(ripple_vertex[i][j].x);
- t2f(ripple_vertex[i][j + 1].t);
- v2f(ripple_vertex[i][j + 1].x);
- t2f(ripple_vertex[i + 1][j + 1].t);
- v2f(ripple_vertex[i + 1][j + 1].x);
- t2f(ripple_vertex[i + 1][j].t);
- v2f(ripple_vertex[i + 1][j].x);
- endpolygon();
- }
- }
-
- swapbuffers();
- }
-
- /*
- Calculate the distance between two points.
- */
-
- float ripple_distance(int gx, int gy, int cx, int cy)
- {
- return sqrt(1.0*(gx - cx)*(gx - cx) + 1.0*(gy - cy)*(gy - cy));
- }
-
- /*
- Compute the distance of the given window coordinate
- to the nearest window corner, in pixels.
- */
-
- int ripple_max_distance(int gx, int gy)
- {
- float d;
- float temp_d;
-
- d = ripple_distance(gx, gy, 0, 0);
- temp_d = ripple_distance(gx, gy, GRID_SIZE_X, 0);
- if (temp_d > d)
- d = temp_d;
- temp_d = ripple_distance(gx, gy, GRID_SIZE_X, GRID_SIZE_Y);
- if (temp_d > d)
- d = temp_d;
- temp_d = ripple_distance(gx, gy, 0, GRID_SIZE_Y);
- if (temp_d > d)
- d = temp_d;
-
- return (d/GRID_SIZE_X)*WIN_SIZE_X + RIPPLE_LENGTH/6;
- }
-
- /*
- Generate a new ripple when the mouse is pressed. There's
- a limit on the number of ripples that can be simultaneously
- generated.
- */
-
- void ripple_click(int mousex, int mousey, int state)
- {
- int index;
-
- if (state)
- {
- index = 0;
- while (t[index] < max[index] && index < RIPPLE_COUNT)
- index++;
-
- if (index < RIPPLE_COUNT)
- {
- cx[index] = 1.0*mousex/WIN_SIZE_X*GRID_SIZE_X;
- cy[index] = 1.0*mousey/WIN_SIZE_Y*GRID_SIZE_Y;
- t[index] = 4*RIPPLE_STEP;
- max[index] = ripple_max_distance(cx[index], cy[index]);
- }
- }
- }
-